﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Linq.Expressions;

namespace AirLinq.Providers.Sql {
	public class SqlDatabaseProvider : IDatabaseProvider {
		private class ExpressionReviewer : ExpressionVisitor {
			private bool _hasSelect;
			public Expression Review(Expression expression){
				return Visit(expression);
			}
			protected override MethodCallExpression VisitMethodCall(MethodCallExpression exp) {
				if (!_hasSelect) {
					if (exp.Method.GetGenericMethodDefinition() == QueryableMethods.PFromTable) {
						var argType = exp.Method.GetGenericArguments()[0];
						var parameter=Expression.Parameter(argType, "row");
						var selectExpression = Expression.Lambda(parameter,parameter);
						return Expression.Call(QueryableMethods.QSelect1.MakeGenericMethod(argType, argType), exp, selectExpression);
					}
					if (exp.Method.GetGenericMethodDefinition() == QueryableMethods.QSelect1) {
						_hasSelect = true;
					}
				}
				return base.VisitMethodCall(exp);
			}
		}
		#region IDatabaseProvider Members
		public IDbCommand CreateCommand(IDbConnection connection, Expression expressionTree, IQueryProvider provider) {
			var airLinqProvider = provider as AirLinqProvider;
			if (airLinqProvider == null) {
				throw new ArgumentException("'provider' must be AirLinqProviderType");
			}
			var reviewer=new ExpressionReviewer();
			expressionTree=reviewer.Review(expressionTree);
			var visitor=new QueryConverter();
			var sqlTree=visitor.Visit(airLinqProvider, expressionTree);
			
			var generator = new CommandGenerator();
			var command=generator.Process(sqlTree) as IDbCommand;
			command.Connection=connection;
			return command;
		}
		#endregion
	}
}
